package com.gupaoedu.vip.netty.io.nio.tomcat;

import com.gupaoedu.vip.netty.io.nio.tomcat.http.GPRequest;
import com.gupaoedu.vip.netty.io.nio.tomcat.http.GPResponse;
import com.gupaoedu.vip.netty.io.nio.tomcat.http.GPServlet;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * @program:gupaoedu-vip-netty-io
 * @description:使用Netty的Tomcat例子
 * @author:Gongchao
 * @date:2020-04-28
 **/
public class GPTomcat {

    private int port = 8080;

    private Map<String, GPServlet> servletMap = new HashMap<String, GPServlet>();

    private Properties webxml = new Properties();

    private void init() {
        //加载web.xml，同时初始化ServletMapping
        String WEB_INFO = this.getClass().getResource("/").getPath();
        try {
            FileInputStream fileInputStream = new FileInputStream(WEB_INFO+"web.properties");

            webxml.load(fileInputStream);

            for(Object k : webxml.keySet()) {
                String key = k.toString();
                if(key.endsWith(".url")) {
                    String servletName = key.replaceAll("\\.url$","");
                    String url = webxml.getProperty(key);
                    String className = webxml.getProperty(servletName+".className");
                    GPServlet obj = (GPServlet) Class.forName(className).newInstance();
                    servletMap.put(url,obj);
                }
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public void start() {
        init();

        //Netty封装了NIO，Reator模型，boss线程，worker线程
        //boss线程
        EventLoopGroup bossGrop = new NioEventLoopGroup();
        //worker线程
        EventLoopGroup workerGrop = new NioEventLoopGroup();
        try {
            //Netty服务
            //ServerBootstrap ServerSockerChannel
            ServerBootstrap server = new ServerBootstrap();
            //链路式编程
            server.group(bossGrop,workerGrop)
                    //主线程处理类，使用反射实现
                    .channel(NioServerSocketChannel.class)
                    //子线程处理类，Handler
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        //客户端初始化
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            //无锁化串行编程
                            //Netty对HTTP协议的封装，顺序有要求
                            //HttpResponseEncoder 编码器
                            socketChannel.pipeline().addLast(new HttpResponseEncoder());
                            //HttpRequestDecoder 解码器
                            socketChannel.pipeline().addLast(new HttpRequestDecoder());
                            //业务逻辑处理
                            socketChannel.pipeline().addLast(new GPTomcatHandler());
                        }
                    })
                    //针对主线程的配置，分配线程最大数量 128
                    .option(ChannelOption.SO_BACKLOG,128)
                    //针对子线程的配置 保持长连接
                    .childOption(ChannelOption.SO_KEEPALIVE,true);
            //启动服务
            ChannelFuture channelFuture = server.bind(port).sync();
            System.out.println("GPTomcat 已启动，监听的端口为："+this.port);
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            //关闭线程池
            bossGrop.shutdownGracefully();
            workerGrop.shutdownGracefully();
        }
    }

    public class GPTomcatHandler extends ChannelInboundHandlerAdapter{
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//            super.channelRead(ctx, msg);
            if(msg instanceof HttpRequest) {
                HttpRequest req = (HttpRequest) msg;

                //转交给自己定义的request实现
                GPRequest request = new GPRequest(ctx,req);
                //转交给自己定义的response实现
                GPResponse response = new GPResponse(ctx,req);
                //实际业务处理
                String url = request.getUrl();

                if(servletMap.containsKey(url)) {
                    servletMap.get(url).service(request,response);
                }else {
                    response.write("404 -NOT Found");
                }
            }
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            super.exceptionCaught(ctx, cause);
        }
    }

    public static void main(String[] args) {
        new GPTomcat().start();
    }
}
